import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { isEmail, isMobilePhone } from 'class-validator';
import { usernameReg } from 'src/utils/reg';
import { In, Repository } from 'typeorm';
import { TokenEntity } from '../auth/entities/token.entity';
import { ResourceEntity } from '../resource/entities/resource.entity';
import { ResourceRoleEntity } from '../resource/entities/resource.role.entity';
import { ResourceService } from '../resource/resource.service';
import { CreateUserDto } from './dto/create.user.dto';
import { UserEntity } from './entities/user.entity';
import { UserRoleEntity } from './entities/user.role.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepository: Repository<UserEntity>,
    @InjectRepository(ResourceEntity)
    private readonly resourceRepository: Repository<ResourceEntity>,
    @InjectRepository(ResourceRoleEntity)
    private readonly resourceRoleRepository: Repository<ResourceRoleEntity>,
    private readonly resourceService: ResourceService,
  ) {}

  /**
   * @Author: laotongshu
   * @Date: 2022-09-24 10:36:28
   * @LastEditors: laotongshu
   * @Description: 获取用户信息
   * @param {header} {header}
   * @return {*}
   */
  async getUser(header) {
    const { token } = header;
    // SELECT t2.* FROM token t1, user t2 WHERE t1.user_id = t2.id AND t1.token = token
    const qb = await UserEntity.getRepository().createQueryBuilder('user');
    // const res = await qb
    //   .innerJoinAndSelect('user.userRoles', 'userRoles')
    //   .leftJoinAndSelect(TokenEntity, 'token', `token.token = ${token}`)
    //   .leftJoinAndSelect(UserRoleEntity, 'userRole')
    //   .leftJoinAndSelect(
    //     ResourceRoleEntity,
    //     'resourceRole',
    //     'resourceRole.roleId = userRole.roleId',
    //   )
    //   .getMany();
    const res = await qb
      .where((qb) => {
        const userId = qb
          .subQuery()
          .select('token.user_id')
          .from(TokenEntity, 'token')
          .where('token.token = :token')
          .getQuery();
        return 'user.id = ' + userId;
      })
      .setParameter('token', token)
      .getOne();
    return res;
    // 第二种方法
    //   const tokenInfo = await TokenEntity.createQueryBuilder('token')
    //     .where('token.token = :token', {
    //       token: token,
    //     })
    //     .select('token.userId', 'userId')
    //     .addSelect((s) => s.select('id').from(UserEntity, 'user').where('token.userId=user.id'), 'id')
    //     .addSelect(
    //       (s) => s.select('mobile').from(UserEntity, 'user').where('token.userId=user.id'),
    //       'mobile',
    //     )
    //     .addSelect(
    //       (s) => s.select('username').from(UserEntity, 'user').where('token.userId=user.id'),
    //       'username',
    //     )
    //     .getRawOne();
    //   console.log('2022-09-23 14:28:29', tokenInfo);
    //   return tokenInfo;
  }

  /**
   * @Author: laotongshu
   * @Date: 2022-09-20 14:09:10
   * @LastEditors: laotongshu
   * @Description: 创建用户
   * @param
   * @return {*}
   */
  async createUser(createUserDto: CreateUserDto): Promise<string> {
    const { username, email, mobile } = createUserDto;
    const queryConditionList = [];
    if (username) {
      queryConditionList.push('user.username = :username');
    }
    if (email) {
      queryConditionList.push('user.email = :email');
    }
    if (mobile) {
      queryConditionList.push('user.mobile = :mobile');
    }
    const queryCondition = queryConditionList.join(' OR ');
    const findAccount = await this.userRepository
      .createQueryBuilder('user')
      .select(['user.username', 'user.email', 'user.mobile'])
      .andWhere(queryCondition, { username, email, mobile })
      .getOne();
    console.log('2022-09-28 11:08:59', findAccount);
    if (findAccount) {
      const { username, email, mobile } = findAccount;
      if (username) {
        return '创建失败,已经存在该用户名';
      } else if (isMobilePhone(mobile, 'zh-CN')) {
        return '创建失败,已经存在该手机号码';
      } else if (isEmail(email)) {
        return '创建失败,已经存在该邮箱号';
      } else {
        return '创建失败';
      }
    } else {
      if (username && !usernameReg.test(username)) {
        return '用户名由数字和字母组成，且4-20位';
      } else if (mobile && !isMobilePhone(mobile, 'zh-CN')) {
        return '手机号码不正确';
      } else if (email && !isEmail(email)) {
        return '邮箱不正确';
      }
      const account: UserEntity = this.userRepository.create({
        ...createUserDto,
      });
      const saveUser = await this.userRepository.save(account);
      console.log('2022-09-28 11:08:12', saveUser);
      return '创建成功';
    }
  }

  /**
   * @Author: laotongshu
   * @Date: 2022-10-11 14:59:59
   * @LastEditors: laotongshu
   * @Description: 给用户绑定角色
   * @param {Object} {}
   * @return {*}
   */
  async bindRole(userId, roleId) {
    const user = await UserEntity.getRepository()
      .createQueryBuilder('user')
      .where({ id: userId })
      .leftJoinAndSelect('user.userRoles', 'userRoles')
      .getOne();
    if (user.userRoles?.length > 0) return '一个用户只能绑定一个角色';
    const userRole = new UserRoleEntity();
    userRole.roleId = roleId;
    userRole.userId = user.id;
    user.userRoles = [userRole];
    console.log('2022-10-12 09:26:52', user);
    const result = this.userRepository.create(user);
    return await this.userRepository.save(result);
  }

  /**
   * @Author: laotongshu
   * @Date: 2022-10-11 18:09:59
   * @LastEditors: laotongshu
   * @Description: 根据角色Id获取资源
   * @param {Object} {}
   * @return {*}
   */
  async resourceById(roleId) {
    const res = await this.resourceRoleRepository
      .createQueryBuilder('resourceRole')
      .where('resourceRole.roleId = :roleId', { roleId })
      .getMany();
    const ids = res.map((item) => item.resourceId);
    const resource = await this.resourceRepository.find({
      where: {
        id: In(ids),
      },
    });
    const resourcePromise = resource.map(async (item) => {
      const children = await this.resourceService.roleList(item.id);
      return {
        ...item,
        children,
      };
    });
    const result = await Promise.all(resourcePromise);
    return result;
  }
}
